﻿/**
 * Copyright (C) 2012-2013 original author and authors
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using NGuice.Inject.Spi;
using NGuice.Inject.Internal.Util;

namespace NGuice.Inject.Internal
{
    /// <summary>
    /// 一个占位符，此占位符一旦注入器被创建即允许我们在实际的工厂中切换。用于一个链接的绑定，
    /// 因此获取链接的绑定将返回链接的工厂
    /// <remarks>
    /// 此接口的Notify方法可以作为BindingProcessor.CreationListener的事件加入其中
    /// </remarks>
    /// </summary>
    /// <typeparam name="T"></typeparam>
    internal sealed class FactoryProxy<T> : InternalFactory<T>
    {
        private readonly InjectorImpl injector;
        private readonly Key<T> key;
        private readonly Key targetKey;
        private readonly object source;

        private InternalFactory targetFactory;//泛型参数必须为T的子类

        public  FactoryProxy(InjectorImpl injector, Key<T> key, Key targetKey, object source)
        {
            this.injector = injector;
            this.key = key;
            this.targetKey = targetKey;
            this.source = source;
        }

        /// <summary>
        /// 用于BindingProcessor的CreationNotify事件方法
        /// </summary>
        /// <param name="errors"></param>
        public void Notify(Errors errors)
        {
            try
            {
                targetFactory = injector.GetInternalFactory(targetKey, errors.WithSource(source), InjectorImpl.JitLimitation.NEW_OR_EXISTING_JIT);
            }
            catch (ErrorsException e)
            {
                errors.Merge(e.Errors);
            }
        }

        public T Get(Errors errors, InternalContext context, Dependency dependency, bool linked)
        {
            return (T)targetFactory.Get(errors.WithSource(targetKey), context, dependency, true);
        }

        public override string ToString()
        {
            return new ToStringBuilder(typeof(FactoryProxy<>))
                .Add("key", key)
                .Add("provider", targetFactory)
                .ToString();
        }

        object InternalFactory.Get(Errors errors, InternalContext context, Dependency dependency, bool linked)
        {
            return Get(errors,context, dependency, linked);
        }
    }
}
